#pragma once
#include <brpc/channel.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include "logger.hpp"

// 1. 封装单个服务的信道管理类
class ServiceChannel{
public:
    using ptr = std::shared_ptr<ServiceChannel>;    // 类型别名 简化使用
    using ChannelPtr = std::shared_ptr<brpc::Channel>;
    ServiceChannel(const std::string& name)
        :_service_name(name), _index(0) 
    {}
    // 1. 服务上线新节点, 调用 append 新增信道
    void append(const std::string &host){
        // 1. 创建信道
        auto channel = std::make_shared<brpc::Channel>();
        // 2. 配置 ChannelOptions
        brpc::ChannelOptions options;
        options.connect_timeout_ms = -1;    // 连接等待超时时间
        options.timeout_ms = -1;            // rpc请求等待超时时间
        options.max_retry = 3;              // 请求重试次数
        options.protocol = "baidu_std";     // 序列化协议，默认使用baidu_std
        // 3. 信道初始化
        if(channel->Init(host.c_str(), &options) == -1){
            LOG_ERROR("初始化{}-{}信道失败", _service_name, host);
            return;
        }
        // 4. 加锁 & 添加数据
        std::unique_lock<std::mutex> lock(_mutex);
        _hosts.insert(std::make_pair(host, channel));
        _channels.push_back(channel);
    }
    // 2. 服务下线新节点, 调用 remove 释放信道
    void remove(const std::string &host){
        // 1. 查找释放存在该信道
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _hosts.find(host);
        if(it == _hosts.end()){
            LOG_WARN("{}-{}节点删除信道时，没有找到信道信息！", _service_name, host);
            return;
        }
        // 2. 遍历信道列表删除信道
        for(auto i = _channels.begin(); i != _channels.end(); ++i){
            if(*i == it->second){
                _channels.erase(i);
                break;
            }
        }
        _hosts.erase(it); // 记得清除对应映射
    }
    // 3. 获取 Channel 用于发起对应服务的 Rpc 调用 -- RR 轮转策略
    ChannelPtr choose(){
        std::unique_lock<std::mutex> lock(_mutex);
        if(_channels.size() == 0){
            LOG_ERROR("当前没有能够提供 {} 服务的节点！", _service_name);
            return ChannelPtr();
        }
        int idx = _index++ % _channels.size();
        return _channels[idx];
    }
private:
    std::mutex _mutex;
    int32_t _index;                                     // 轮询计数器
    std::string _service_name;                          // 服务名称
    std::vector<ChannelPtr> _channels;                  // 信道列表（用于轮询）
    std::unordered_map<std::string, ChannelPtr> _hosts; // 主机地址与信道映射关系
};


// 2. 总体的服务信道管理类
class ServiceManager {
public:
    using ptr = std::shared_ptr<ServiceManager>;
    ServiceManager() {}
    // 1. 为指定服务选择一个可用的 Channel（用于发起 RPC）
    ServiceChannel::ChannelPtr choose(const std::string &service_name) {
        std::unique_lock<std::mutex> lock(_mutex);
        // 1. 查找是否存在
        auto sit = _services.find(service_name);
        if(sit == _services.end()){
            LOG_ERROR("当前没有能够提供 {} 服务的节点！", service_name);
            return ServiceChannel::ChannelPtr();
        }
        // 2. RR 策略选择
        return sit->second->choose();
    }
    // 2. 声明我关注某个服务，注意 不关心的就不用管理
    void declared(const std::string &service_name) {
        std::unique_lock<std::mutex> lock(_mutex);
        _follow_services.insert(service_name);
    }
    // 3. 处理“服务上线”事件，添加新节点
    void onServiceOnline(const std::string &service_instance, const std::string &host) {
        // 1. 解析服务名
        std::string service_name = getServiceName(service_instance);
        ServiceChannel::ptr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 2. 检查是否关注该服务
            auto fit = _follow_services.find(service_name);
            if (fit == _follow_services.end()) {
                LOG_DEBUG("{}-{} 服务上线了，但是当前并不关心！", service_name, host);
                return;
            }
           // 3. 获取/创建 对应的 ServiceChannel
            auto sit = _services.find(service_name);
            if (sit == _services.end()) {
                // 不存在则创建
                service = std::make_shared<ServiceChannel>(service_name);
                _services.insert(std::make_pair(service_name, service));
            }else {
                service = sit->second;
            }
        }
        if (!service) {
            LOG_ERROR("新增 {} 服务管理节点失败！", service_name);
            return ;
        }
        // 4. 添加信道
        service->append(host);
        LOG_DEBUG("{}-{} 服务上线新节点，进行添加管理！", service_name, host);
    }
    // 4. 处理“服务下线”事件，删除节点 
    void onServiceOffline(const std::string &service_instance, const std::string &host) {
        // 1. 解析服务名
        std::string service_name = getServiceName(service_instance);
        ServiceChannel::ptr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 2. 检查是否关注
            auto fit = _follow_services.find(service_name);
            if (fit == _follow_services.end()) {
                LOG_DEBUG("{}-{} 服务下线了，但是当前并不关心！", service_name, host);
                return;
            }
            // 3. 查找对应 服务信道
            auto sit = _services.find(service_name);
            if(sit == _services.end()){
                LOG_WARN("删除{}服务节点时，没有找到管理对象", service_name);
                return;
            }
            service = sit->second;
        }
        // 4. 调用 remove 删除信道
        service->remove(host);
        LOG_DEBUG("{}-{} 服务下线节点，进行删除管理！", service_name, host);
    }
private:
    // 从服务实例路径提取服务名
    // 如: /service/user/127.0.0.1:8080  --->  /service/user
    std::string getServiceName(const std::string &service_instance) {
        auto pos = service_instance.find_last_of('/');
        if (pos == std::string::npos) return service_instance;
        // 提取字符串
        return service_instance.substr(0, pos);
    }
private:
    std::mutex _mutex;
    std::unordered_set<std::string> _follow_services;               // 关心哪些服务
    std::unordered_map<std::string, ServiceChannel::ptr> _services; // 服务名 -> ServiceChannel
};